package de.g18.scavengerhunt.service;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Message;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import de.g18.scavengerhunt.AppConstants;
import de.g18.scavengerhunt.activity.GameMapActivity;

/**
 *  This class is listening the orientation changes on the compass
 */
public class CompassGateway implements SensorEventListener {

    private String           LOG_TAG                   = this.getClass().getSimpleName();

    private final static int AZIMUTH_UPDATE_INTERVAL = 5;

    private SensorManager    sensorManager             = null;

    private Sensor           compasSensor              = null;
    
    private Display          deviceDisplay 				= null;	

    private GameMapActivity  mapActivity               = null;

    private int              prevAzimuth               = -AZIMUTH_UPDATE_INTERVAL;

    public CompassGateway(GameMapActivity mapActivity) {
        this.mapActivity = mapActivity;
        sensorManager = (SensorManager) mapActivity.getSystemService(Context.SENSOR_SERVICE);
        compasSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        // get display from windowmanager, to obtain screen orientation
     	deviceDisplay = ((WindowManager) mapActivity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    }

    /**
     * Starts using the magnetic field sensor listener.
     */
    public void start() {
        Log.d(LOG_TAG, "Starting Compass Service");
        sensorManager.registerListener(this, compasSensor, SensorManager.SENSOR_DELAY_UI);
    }

    /**
     * Stops using the magnetic field sensor listener.
     */
    public void stop() {
        Log.d(LOG_TAG, "Stopping Compass Service");
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // do nothing
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        // 0 = north, 90 = east and so on... 450 is east again
    	int azimuthNoOffset = (int) sensorEvent.values[0];
        // handle orientation changes only, when orientation is over a defined threshold
        if (Math.abs(azimuthNoOffset - prevAzimuth) > AZIMUTH_UPDATE_INTERVAL) {
        	int azimuth = getAzimuthWithOffset(azimuthNoOffset);
            prevAzimuth = azimuth;
            Log.d(LOG_TAG, "onSensorChanged [azimuth=" + azimuth + "]");
            Message msg = Message.obtain();
            msg.what = AppConstants.UPDATE_COMPASS;
            msg.obj = azimuth;
            mapActivity.onOverlayUpdate(msg);
        }
    }
    
    /**
	 * as the azimuth is always calculated to the top of the device,
	 * we need to calculate an offset, if the device is rotated
	 * 
	 * @param azimuth from sensor
	 * @return azimuth with offset
	 */
	private int getAzimuthWithOffset(int azimuth) {
		int rotation = deviceDisplay.getRotation();
		switch (rotation) {
		case Surface.ROTATION_0:
			//do nothing
			break;
		case Surface.ROTATION_90:
			azimuth += 90;
			break;
		case Surface.ROTATION_180:
			azimuth += 180;
			break;
		case Surface.ROTATION_270:
			azimuth += 270;
		}
		if (azimuth >= 360) {
			azimuth = azimuth - 360;
		}
		return azimuth;
	}

    public int getLastAzimuth() {
        return prevAzimuth == AZIMUTH_UPDATE_INTERVAL ? 0 : prevAzimuth;
    }
}